package com.corticon.dialogs.web.designer;

import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.security.DisabledException;
import org.springframework.security.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.ModelMap;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.support.SessionStatus;

import com.corticon.dialogs.model.User;
import com.corticon.dialogs.service.PortalUserService;
import com.corticon.dialogs.util.security.PasswordNotMatchException;
import com.corticon.dialogs.validation.UserValidator;
import com.corticon.dialogs.validation.ValidationMessageFormatter;
import com.corticon.dialogs.web.BaseController;

/**
 * Reset password controller.
 *
 * @author Minghui Zheng
 */
@Controller
public class ResetPasswordController extends BaseController {

    private Log logger = LogFactory.getLog(ResetPasswordController.class);
    @Resource
    private PortalUserService portalUserService;
    private PasswordValidator passwordValidator;
    //Returned view
    private static final String RESET_PASSWORD_VIEW = "designer.general.resetpassword";
    private static final String LOGIN_PAGE = "/login.jsp";
    private static final String DIALOG_INDEX_PAGE = "/designer/questionnaire/list.html";

    /**
     * Instantiate the validators after the construct method.
     * This method will be auto invoked.
     */
    @PostConstruct
    private void buildValidators() {
        passwordValidator = new PasswordValidator(validationMessageFormatter);
    }

    /**
     * Login user, if pass authentication, show reset password page.
     *
     * @param user
     * @param request
     * @return reset password page
     */
    @Transactional
    @RequestMapping(value = "resetpass", method = RequestMethod.POST)
    public String entryResetPassword(HttpServletRequest request, ModelMap model) {

        logger.debug("--------Run entry reset password: " + request.getParameter("username"));

        //get parameters from request.
        User guest = new User();
        guest.setUsername(request.getParameter("username"));
        guest.setPassword(request.getParameter("password"));

        //reset messages in session.
        String[] messagesKeys = {"userdesabled", "errors_username", "errors_password"};
        this.cleanMessages(messagesKeys, request);

        User user = null;
        try {
            user = portalUserService.userLogin(guest, request);
        } catch (DisabledException de) {
            request.getSession().setAttribute("userdesabled", de.getMessage());
            logger.debug("--------------------------Login failed: This account has bean disabled.");
        } catch (UsernameNotFoundException ue) {
            request.getSession().setAttribute("errors_username", ue.getMessage());
        } catch (PasswordNotMatchException pe) {
            request.getSession().setAttribute("errors_password", pe.getMessage());
        }

        request.getSession().setAttribute("LAST_USERNAME_KEY", guest.getUsername());

        if (user != null) {//if pass authentication
            model.addAttribute("user", user);
            return RESET_PASSWORD_VIEW;
        } else {
            //if failed authentication
            request.getSession().setAttribute("hasErrors", true);
        }

        return this.redirectPrefix + LOGIN_PAGE;
    }

    @Transactional
    @RequestMapping(value = "doresetpass", method = RequestMethod.POST)
    public String doResetPassword(@ModelAttribute("user") User user, Errors errors,
                                  HttpServletRequest request, SessionStatus sessionStatus) {

        this.doValidate(user, errors, request);

        if (errors.hasErrors()) {
            logger.debug("-----------------------------do reset error.");

            request.setAttribute("hasErrors", true);
            return RESET_PASSWORD_VIEW;
        }
        //reset password
        portalUserService.resetPassword(user);

        logger.debug("---------after reset password");

        request.getSession().setAttribute("LAST_USERNAME_KEY", user.getUsername());

        //redirect to main page.
        return this.redirectPrefix + DIALOG_INDEX_PAGE;
    }

    private void doValidate(User user, Errors errors, HttpServletRequest request) {
        //Validate the form object.
        passwordValidator.passwordValidate(user, errors);
        Map<String, List<String>> errorsMessages = validationMessageFormatter.
                convertErrorsMessageToMap(user, errors, request.getLocale());

        //Put error messages into request.
        request.setAttribute("errors", errorsMessages);
    }

    private class PasswordValidator extends UserValidator<User> {

        public PasswordValidator(ValidationMessageFormatter validationMessageFormatter) {
            super.validationMessageFormatter = validationMessageFormatter;
        }

        @Override
        public void passwordValidate(User user, Errors errors) {

            if (user.getPassword().length() < 6 || user.getPassword().length() > 12) {
                errors.rejectValue("password", "validate.user.password.invalid",
                        "This password is invalid; passwords must be " +
                                "between 6 and 12 characters consisting of at least 1 alpah and at least 1 numeric characters");
            }

            super.passwordValidate(user, errors);
        }
    }
}
